package top.ninwoo.utils.util.impl;

import com.spotify.docker.client.DockerClient;
import com.spotify.docker.client.LogStream;
import com.spotify.docker.client.exceptions.ContainerNotFoundException;
import com.spotify.docker.client.exceptions.DockerException;
import com.spotify.docker.client.messages.Container;
import com.spotify.docker.client.messages.ContainerInfo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import top.ninwoo.common.entity.DockerContainer;
import top.ninwoo.utils.util.DockerUtils;
import top.ninwoo.utils.util.LinuxCtlUtils;
import top.ninwoo.utils.util.Utils;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @Author joliu
 * @Description
 * @Date　Create in 下午9:26 2019/10/20
 */
@Utils
public class DockerUtilsImpl implements DockerUtils {
    private final Logger LOG = LoggerFactory.getLogger(DockerUtilsImpl.class);

    @Autowired
    DockerClient dockerClient;

    @Autowired
    LinuxCtlUtils linuxCtlUtils;


    @Override
    public Map<String, DockerContainer> getContainers() {
        return getContainers(false);
    }

    @Override
    public Map<String, DockerContainer> getContainers(boolean isAll) {
        HashMap<String, DockerContainer> containersMap = new HashMap<>();
        containersMap.clear();
        List<Container> containers =
                null;
        try {
            if(!isAll) {
                containers = dockerClient.listContainers(DockerClient.ListContainersParam.withStatusRunning());
            } else {
                // TODO:这里边还需要在确定
                containers = dockerClient.listContainers(DockerClient.ListContainersParam.allContainers());
            }
        } catch (DockerException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        List<DockerContainer> dockerContainers = convertDockerResult(containers);
        dockerContainers.forEach(dockerContainer -> containersMap.put(dockerContainer.getId(), dockerContainer));
        return containersMap;
    }

    /**
     * 将DockerClient获取的到结果封装成为我们自定义的数据结构
     * @param containers
     * @return
     */
    public List<DockerContainer> convertDockerResult(List<Container> containers) {
        if(containers == null) {
            LOG.warn("docker容器列表为null");
            // 返回一个空的列表
            return new ArrayList<>();
        }
        List<DockerContainer> dockerContainers = new ArrayList<DockerContainer>(containers.size());
        containers.forEach(c -> {
            DockerContainer container = new DockerContainer();
            container.setId(c.id());
            container.setCommand(c.command());
            container.setCreated(c.created());
            container.setPorts(c.portsAsString());
            container.setImage(c.image());
            container.setStatus(c.status());
            container.setName(c.names().get(0));
            dockerContainers.add(container);
        });
        return dockerContainers;
    }

    @Override
    public DockerContainer runDocker(DockerContainer container) {
        // TODO: 这里启动Docker容器,需要再研究port如何起作用
        // TODO: 这里还需要处理name等属性为空的情况
        //String cmd = "docker run -itd --name " +  container.getName() + " --privileged " + container.getImage() + " " + container.getCommand();
        String cmd;
        if(container.getPorts() == null){
             // cmd = "docker run -itd --name " +  container.getName() + " --privileged " + container.getImage() + " " + container.getCommand();
            cmd = "docker run -itd -P " + " --name " + container.getName() + " --net=none" + " --privileged " + container.getImage() + " " + container.getCommand();
        }else {
            cmd = "docker run -itd -p " + container.getPorts()+ ":" +container.getPorts()+ " " + "--name " + container.getName() + " --net=none" + " --privileged " + container.getImage() + " " + container.getCommand();
        }

        String result = linuxCtlUtils.runCmd(cmd);
        if(result.contains("Error")) {
            throw new RuntimeException("Run Docker failed!:[" + cmd + "]:" + result);
        }
        // TODO:需要从Docker中查询处完整的信息
        container.setId(result);
        return container;
    }

    /**
     * @descprition 这个是通过docker inspect 【dockerid】返回的接口，数据更新
     * @param id
     * @return
     */
    @Override
    public DockerContainer getDockerById(String id) {
        ContainerInfo containerInfo = null;
        try {
            containerInfo = dockerClient.inspectContainer(id);
        } catch (ContainerNotFoundException e) {
            return null;
        } catch (DockerException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return exchangeFromDockerInfo(containerInfo);
    }

    public DockerContainer exchangeFromDockerInfo(ContainerInfo containerInfo) {
        if(containerInfo == null) {
            throw new RuntimeException("ContainerInfo cannot be null");
        }
        DockerContainer dockerContainer = new DockerContainer();
        dockerContainer.setImage(containerInfo.image());
        dockerContainer.setName(containerInfo.name());
        dockerContainer.setId(containerInfo.id());
        dockerContainer.setStatus(containerInfo.state().status());
        dockerContainer.setCreated(containerInfo.created().getTime());
        return dockerContainer;
    }

    @Override
    public boolean deleteDockerById(String id) {
        try {
            dockerClient.stopContainer(id, 0);
            dockerClient.removeContainer(id);
            return true;
        } catch (DockerException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return false;
    }

    @Override
    public String execInDocker(String containerId, String args) {
        return execInDocker(containerId, args.split(" "));
    }

    @Override
    public String execInDocker(String containerId, String[] args) {
        String result = "";
        try {
            String id = dockerClient.execCreate(containerId, args, DockerClient.ExecCreateParam.attachStdout(),
                    DockerClient.ExecCreateParam.attachStderr()).id();
            try(LogStream logStream = dockerClient.execStart(id)) {
                 result = logStream.readFully();
            }
        } catch (DockerException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * 启动容器
     * @param containerId
     * @return true不一定是启动成功，启动成功还需要通过容器列表来判断
     */
    @Override
    public boolean startContainer(String containerId) {
        try {
            dockerClient.startContainer(containerId);
            return true;
        } catch (DockerException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return false;
    }

    @Override
    public String getDockerIdByName(String name) {
        try {
            return dockerClient.inspectContainer(name).id();
        } catch (DockerException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return "";
    }
}
